"""
Description:
Author: 月间
Date: 2025-10-13 22:40:28
LastEditTime: 2025-10-14 23:33:54
LastEditors:
"""

import logging

# @Version        : 1.0
# @Update Time    : 2025/10/13 22:40
# @File           : middlewares.py
# @IDE            : PyCharm
# @Desc           : 文件描述信息
# middlewares.py
import time
from typing import Set, Callable, Optional

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response

from authx.core.context import AuthContextManager
from authx.settings.config import settings
from authx.utils import get_device_data, get_remote_address

logger = logging.getLogger("authx.session")


class AuthxSessionMiddleware(BaseHTTPMiddleware):
    """
    认证相关的中间件，用于处理用户会话信息
    功能包括：
    - 获取并存储用户IP地址
    - 获取并存储设备信息
    - 记录请求处理时间
    - 处理请求前后的钩子函数
    """

    def __init__(
        self,
        app,
        skip_paths: Optional[Set[str]] = None,
        add_process_time_header: bool = True,
        process_time_header_name: str = "X-Process-Time",
    ):
        """
        初始化中间件

        Args:
            app: ASGI 应用
            skip_paths: 跳过处理的路径集合
            add_process_time_header: 是否添加处理时间响应头
            process_time_header_name: 处理时间响应头名称
        """
        super().__init__(app)
        self.skip_paths = skip_paths or set()
        self.add_process_time_header = add_process_time_header
        self.process_time_header_name = process_time_header_name

    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        """
        处理请求并返回响应

        Args:
            request: 请求对象
            call_next: 下一个处理函数

        Returns:
            Response: 响应对象
        """
        # 检查是否需要跳过当前路径
        AuthContextManager.set_current_request(request)
        if request.url.path in self.skip_paths:
            return await call_next(request)

        # 记录请求开始时间
        start_time = time.perf_counter()

        try:
            # 获取并存储用户IP地址
            request.state.ip_address = await get_remote_address(request)

            # 获取并存储设备信息
            request.state.device_data = await get_device_data(request)

            # 记录请求信息
            if settings.IS_LOG:
                logger.info(
                    f"Request from {request.state.ip_address}: {request.method} {request.url.path}"
                )

            # 处理请求
            response = await call_next(request)

            # 计算处理时间
            process_time = time.perf_counter() - start_time

            # 添加处理时间响应头
            if self.add_process_time_header:
                response.headers[self.process_time_header_name] = str(process_time)

            return response

        except Exception as e:
            # 记录异常信息
            logger.error(
                f"Error processing request {request.method} {request.url.path}: {str(e)}"
            )

            # 重新抛出异常，让上层处理
            raise
        finally:
            AuthContextManager.cleanup_context()
            # 记录请求结束信息
            if settings.IS_LOG:
                process_time = time.time() - start_time
                logger.debug(
                    f"Request {request.method} {request.url.path} completed in {process_time:.4f}s"
                )
